package bancosys.tec.persist.traverse;

import java.util.Collection;
import java.util.Map;

import bancosys.tec.persist.Persistable;
import bancosys.tec.utils.traverser.TraverseException;
import bancosys.tec.utils.traverser.Visitor;

/**
 * Classe que representa um Visitor de persistables
 * 
 * @author pedro
 */
public abstract class PersistableVisitor implements Visitor {

    /**
     * Método que visita um objeto qualquer. Adaptação do padrão ao fato de não se ter um super-tipo de objetos visitáveis, e portanto, não
     * é possível usar double-dispatch. Delega para um método mais adequado.
     * 
     * @param node nó da estrutura que está sendo visitada
     * @throws TraverseException caso ocorra algum erro
     */
    public final void visit(Object node) throws TraverseException {
        if (node == null) {
            return;
        }

        if (node instanceof Persistable) {
            this.visit((Persistable) node);
        } else if (node instanceof Collection<?>) {
            this.visit((Collection<?>) node);
        } else if (node instanceof Map<?, ?>) {
            this.visit((Map<?, ?>) node);
        } else if (node.getClass().isArray()) {
            this.visitArray(node);
        } else {
            this.visitUnknown(node);
        }
    }

    /**
     * Método que visita um objeto persistable
     * 
     * @param persistable objeto persistable a ser visitado
     * @throws TraverseException caso ocorra algum problema durante a visita
     */
    protected abstract void visit(Persistable persistable) throws TraverseException;

    /**
     * Método que visita uma Collection
     * 
     * @param collection Collection
     * @throws TraverseException caso ocorra algum problema durante a visita
     */
    protected abstract void visit(Collection<?> collection) throws TraverseException;

    /**
     * Método que visita uma Collection
     * 
     * @param map Map
     * @throws TraverseException caso ocorra algum problema durante a visita
     */
    protected abstract void visit(Map<?, ?> map) throws TraverseException;

    /**
     * Método que visita uma Collection
     * 
     * @param array Um objeto que representa um array
     * @throws TraverseException caso ocorra algum problema durante a visita
     */
    protected abstract void visitArray(Object array) throws TraverseException;

    /**
     * Método que visita um objeto de tipo inesperado
     * 
     * @param unknown objeto de tipo inesperado
     * @throws TraverseException caso ocorra algum problema durante a visita
     */
    protected abstract void visitUnknown(Object unknown) throws TraverseException;

}
